// cf-464e
// 题意：
// 给定一个n(<=10^5)个点, m(<=10^5)条边的无向图，第i条边的权是
// 2^xi(xi<=10^5)，求s到t的最短路模除10^9+7，然后输出路径，如果
// 没有输出-1。
//
// 题解：
// 除了边权之外就是一个普通的最短路，我们要想办法来维护这个边权。
// 我们可以记录每个权值的二进制表示，这样可以用线段树维护出加一个
// 2^xi的操作，只需要找到xi位开始连续的1, 置零，然后将第一个0置1就行。
// 但是直接这样用线段树存空间爆炸，我们可以用可持久化线段树。
//
// 判相等的时候直接用hash值来判断相等，然后我们可以初始化两个全0和全1
// 的线段树，如果对于置0或者置1操作，就不需要新增节点，直接赋值为对应
// 树上结点就行，这样可以优化不少空间。
//
// ml:run = $bin < input
// ml:opt = 0
// ml:ccf += -g
#include <iostream>
#include <queue>
#include <vector>

int const mo = 1000000007;
int const maxn = 100007;
int const maxv = 10000007;
int const maxl = 1 << 17;
int pow2[maxl + 4];
int n, m, s, t;

struct edge { int to, cost; };

std::vector<std::vector<edge>> graph;

struct node
{
    node() = default;
    node(node* left, node* right) : left(left), right(right)
    {
        if (left && right) update();
    }

    void update()
    {
        len = left->len + right->len;
        firstone = left->firstone == left->len ?
            left->len + right->firstone : left->firstone;
        hash = ((long long)right->hash * pow2[left->len] + left->hash) % mo;
    }

    node* left, *right;
    int len, firstone, hash; // firstone for left continuous ones.
};

node node_pool[maxv], *alloc, *templates[2][maxl + 1];

void add_edge(int u, int v, int c)
{
    graph[u].push_back({v, c});
    graph[v].push_back({u, c});
}

int get_firstone(node* u, int l, int r, int p)
{
    if (l == r) return u->firstone;
    int mid = (l + r) / 2;
    if (p > mid)
        return get_firstone(u->right, mid + 1, r, p);
    int ret = get_firstone(u->left, l, mid, p);
    return ret == mid + 1 - p ? ret + u->right->firstone : ret;
}

node* set_zero(node* u, int l, int r, int tl, int tr)
{
    if (tl <= l && r <= tr)
        return templates[0][r - l + 1];
    int mid = (l + r) / 2;
    if (tr <= mid)
        return new (alloc++) node(set_zero(u->left, l, mid, tl, tr), u->right);
    if (tl  > mid)
        return new (alloc++) node(u->left, set_zero(u->right, mid + 1, r, tl, tr));
    return new (alloc++) node(set_zero(u->left, l, mid, tl, tr), set_zero(u->right, mid + 1, r, tl, tr));
}

node* set_one(node* u, int l, int r, int pos)
{
    if (l == r) return templates[1][1];
    int mid = (l + r) / 2;
    if (pos <= mid)
        return new (alloc++) node(set_one(u->left, l, mid, pos), u->right);
    else
        return new (alloc++) node(u->left, set_one(u->right, mid + 1, r, pos));
}

node* add(node* root, int pow)
{
    int ones = get_firstone(root, 0, maxl - 1, pow);
    if (ones)
        root = set_zero(root, 0, maxl - 1, pow, pow + ones - 1);
    root = set_one(root, 0, maxl - 1, pow + ones);
    return root;
}

int cmp(node* u, node* v)
{
    for (int l = 0, r = maxl - 1; ; ) {
        if (l == r) return u->hash - v->hash;
        int mid = (l + r) / 2;
        if (u->right->hash == v->right->hash) {
            u = u->left;
            v = v->left;
            r = mid;
        } else {
            u = u->right;
            v = v->right;
            l = mid + 1;
        }
    }
}


struct pair
{
    pair() = default;
    pair(node* d, int id) : d(d), id(id) {}

    node* d;
    int id;
};

bool operator<(pair const& a, pair const& b)
{
    return cmp(a.d, b.d) > 0;
}

node* dist[maxn];
int path[maxn];
bool vis[maxn];

void dijkstra(int s)
{
    dist[s] = templates[0][maxl];
    path[s] = -1;
    std::priority_queue<pair> pq;
    pq.push({dist[s], s});
    while (!pq.empty()) {
        int now = pq.top().id; pq.pop();
        if (vis[now]) continue;
        vis[now] = true;

        for (auto const& e : graph[now]) {
            int v = e.to, c = e.cost;
            node* tmp = add(dist[now], c);
            if (cmp(tmp, dist[v]) < 0) {
                dist[v] = tmp;
                path[v] = now;
                pq.push({dist[v], v});
            }
        }
    }
}

void init()
{
    pow2[0] = 1;
    for (int i = 1; i <= maxl; i++)
        pow2[i] = (pow2[i - 1] * 2) % mo;

    alloc = node_pool;
    for (int color = 0; color < 2; color++) {
        templates[color][1] = new (alloc++) node(nullptr, nullptr);
        templates[color][1]->len = 1;
        templates[color][1]->hash = color;
        templates[color][1]->firstone = color;
        for (int i = 2; i <= maxl; i += i) {
            templates[color][i] = new (alloc++) node(templates[color][i / 2], templates[color][i / 2]);
        }
    }

    graph.resize(n);

    for (int i = 0; i < n; i++)
        dist[i] = templates[1][maxl];
}

int main()
{
    std::ios_base::sync_with_stdio(false);
    std::cin >> n >> m;
    init();
    for (int i = 0; i < m; i++) {
        int u, v, w; std::cin >> u >> v >> w;
        add_edge(--u, --v, w);
    }
    std::cin >> s >> t;
    dijkstra(--s);

    if (cmp(dist[--t], templates[1][maxl]) == 0) {
        std::cout << "-1\n";
        return 0;
    }

    std::cout << dist[t]->hash << "\n";
    std::vector<int> ret;
    for (int u = t; ; u = path[u]) {
        ret.push_back(u);
        if (u == s) break;
    }

    std::cout << ret.size() << "\n";
    for (int i = ret.size() - 1; i >= 0; i--) {
        std::cout << ret[i] + 1;
        if (i) std::cout << " ";
    }
    std::cout << "\n";
}

